package fr.cephb.doipdf;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.InvalidPropertiesFormatException;
import java.util.Properties;


import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;


import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.GetMethod;


import fr.cephb.io.IOUtils;
import fr.cephb.xhtml.XHTML;
import fr.cephb.xml.XML;

/**
 * Doi2PdfServlet
 *
 */
public class Doi2PdfServlet extends HttpServlet
	{
	private static final long serialVersionUID = 1L;
	
	/** password , if required */
	private String password=null;
	/** session timeout in minutes */
	//private int timeout_minutes =60*24*30;//30 days
	/** examples */
	private String examples=null;
	
	
	
	@Override
	public void init() throws ServletException
		{
		InputStream in=getServletContext().getResourceAsStream("/WEB-INF/properties.xml");
		if(in!=null)
			{
			Properties props=new Properties();
			try
				{
				props.loadFromXML(in);
				in.close();
				this.password=props.getProperty("password");
				this.examples=props.getProperty("examples");
				}
			catch (InvalidPropertiesFormatException e)
				{
				throw new ServletException(e);
				}
			catch (IOException e)
				{
				throw new ServletException(e);
				}
			}
		}
	
	@Override
	protected void service(
			HttpServletRequest req,
			HttpServletResponse res)
			throws ServletException, IOException
		{
		
		String uri= req.getParameter("uri");
		if(uri!=null) uri=uri.trim();
		if(uri!=null && uri.length()==0)
			{
			uri=null;
			}
		//check password filled
		if(this.password!=null)
			{
			HttpSession session= req.getSession(false);
			String pass= req.getParameter("password");
			if(pass==null && session==null)
				{
				req.setAttribute("message", "<div>Password required</div>");
				login(req,res);
				return;
				}
			else if(!this.password.equals(pass) && session==null)
				{
				req.setAttribute("message", "<div>Wrong Password</div>");
				login(req,res);
				return;
				}
			else if(session==null)
				{
				session=req.getSession();
				//session.setMaxInactiveInterval(this.timeout_minutes*60);//
				}
			}
		
		
		
		if(uri==null)
			{
			login(req,res);
			return;
			}
		else
			{
			try
				{
				Doi2PdfResolver app= new Doi2PdfResolver();
				String pdf= app.resolve(uri);
				app=null;
				if(pdf==null)
					{
					req.setAttribute("message", "<div>Cannot resolve "+ XML.escape(uri)+"</div>");
					login(req,res);
					return;
					}
				downloadpdf(req,res,pdf);
				return;
				}
			catch (Exception e)
				{
				req.setAttribute("message", "<div>Error"+ XML.escape(e.getMessage())+"</div>");
				req.setAttribute("exception",e);
				login(req,res);
				return;
				}
			}
		
		
		
		}
	
	
	
	private void downloadpdf(
			HttpServletRequest req,
			HttpServletResponse res,
			String pdf
			)
		throws ServletException, IOException
			{
			HttpClient httpClient=createHttpClient();
			GetMethod method=null;
			try
				{
				final String anchor="<a href='"+XML.escape(pdf)+"'>"+XML.escape(pdf)+"</a>";
				
				method= new GetMethod(pdf);
				if(httpClient.executeMethod(method)!=200)
					{
					req.setAttribute("message", "<div>Cannot get PDF: '"+anchor+"'</div>");
					login(req,res);
					return;
					}
				Header header=method.getResponseHeader("Content-Type");
				if(header==null)
					{
					req.setAttribute("message", "<div>Cannot get content-type for: '"+anchor+"'</div>");
					login(req,res);
					return;
					}
				if(!header.getValue().toLowerCase().startsWith("application/pdf"))
					{
					req.setAttribute("message", "<div>Not a PDF: '"+anchor+"'</div>");
					login(req,res);
					return;
					}
				
				Header len =method.getResponseHeader("Content-Length");
				res.setContentType("application/pdf");
				if(len!=null && len.getValue().matches("\\d+"))
					{
					res.setContentLength(Integer.parseInt(len.getValue()));
					}
				InputStream in=method.getResponseBodyAsStream();
				OutputStream out=res.getOutputStream();
				IOUtils.copyTo(in, out);
				out.flush();
				out.close();
				return;
				}
			finally
				{
				if(method!=null) method.releaseConnection();
				}
			}
	
	private HttpClient createHttpClient()
		{
		HttpClient httpClient=new HttpClient();
		httpClient.getParams().setConnectionManagerTimeout(30*1000L);//
		return httpClient;
		}
	
	
	
	
	/**
	 * login
	 * @param req
	 * @param res
	 * @throws ServletException
	 * @throws IOException
	 */
	private void login(
			HttpServletRequest req,
			HttpServletResponse res)
			throws ServletException, IOException
			{
			res.setContentType(XHTML.MIME_TYPE);
			PrintWriter out= res.getWriter();
			out.println(XHTML.DOCTYPE);
			out.println(
			"<html xmlns='"+XHTML.NS+"\'>" +
			"<body>");
			
			Object message=req.getAttribute("message");
			if(message!=null)
				{
				out.println(String.valueOf(message));
				}
			
			out.println( "<form method='POST' action='getpdf'>");
			
			String uri=req.getParameter("uri");
			out.println("<label for='uri'>URI:</label><input id='uri' name='uri' value='"+
				(uri==null?"":XML.escape(uri))+
				"'/><br/>");
			
			
			if(this.password!=null && req.getSession(false)==null)
				{
				out.println(
					"<label for='password'>Password:</label>" +
					"<input id='password' type='password' name='password'/>"+
					"<br/>"
					);	
				}
			
			
			out.println("<input type='submit'/></form>" );
			
			if(this.examples!=null)
				{
				out.print(this.examples);
				}
			
			Exception error=Exception.class.cast(req.getAttribute("exception"));
			if(error!=null)
				{
				if(error!=null)
					{
					out.print("<!-- ");
					StringWriter sw=new StringWriter();
					PrintWriter pw= new PrintWriter(sw);
					error.printStackTrace(pw);
					XML.escape(out, sw.toString());
					out.print(" -->");
					}
				}
			out.println("<hr/>This bookmarklet will bring up a new window containing the 'getpdf' form from any page on the Web:");
			out.println("<a href='javascript:");
			
			final String bookmarklet= 
					"url=(document.getSelection()?document.getSelection().toString():location.href);" +
					"w=open('"+req.getRequestURL()+ "?uri='+encodeURIComponent(url),'Search PDF','width=720,height=755,scrollbars,resizable');" +
					"void(w.setTimeout('w.focus()',200));"
					;
			out.println(XML.escape(bookmarklet));
			out.println("' title='drag me to your tootlbar'>GetPDF</a>");
			
			out.println("</body></html>");
			out.flush();
			out.close();
			}
	
	
	}
